package com.hmall.search.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hmall.common.client.ItemClient;
import com.hmall.search.mapper.ItemMapper;
import com.hmall.search.pojo.Item;
import com.hmall.search.pojo.ItemDoc;
import com.hmall.search.pojo.PageDTO;
import com.hmall.search.pojo.RequestParams;
import com.hmall.search.service.ItemService;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.rmi.CORBA.ValueHandler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ItemServiceImpl implements ItemService {
    //定义全局静态产量索引库名“item”
    private static final String INDEX_NAME = "item";

    //注入RestHighLevelClient对象
    @Autowired(required = false)
    private RestHighLevelClient highLevelClient;

    //注入itemMapper
    @Autowired(required = false)
    ItemMapper itemMapper;
    /**
     * 自动补全查询
     *
     * @param key
     * @return List
     */
    @Override
    public List<String> suggestion(String key) {
        try {
            SearchRequest request = new SearchRequest(INDEX_NAME);

            //添加补全条件
            request.source().suggest(new SuggestBuilder()
                    .addSuggestion("itemSuggestion", //别名
                            SuggestBuilders
                                    .completionSuggestion("suggestion") //自动不全字段
                                    .prefix(key) //搜索的字段
                                    .skipDuplicates(true) //去掉重复
                                    .size(10)//限制长度
                    ));
            //执行搜索
            SearchResponse response = highLevelClient.search(request, RequestOptions.DEFAULT);

            //获取自动补全结果
            Suggest suggest = response.getSuggest();
            CompletionSuggestion completionSuggestion = suggest.getSuggestion("itemSuggestion");

            List<CompletionSuggestion.Entry.Option> options = completionSuggestion.getOptions();
            //定义集合存储结果
            ArrayList<String> result = new ArrayList<>();
            for (CompletionSuggestion.Entry.Option option:options){
                String text = option.getText().toString();
                result.add(text);
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 过滤聚合
     *
     * @param requestParams
     * @return
     */
    @Override
    public Map<String, List<String>> filters(RequestParams requestParams) {
        try {
            SearchRequest request = new SearchRequest(INDEX_NAME);
            //构建条件
            //bool查询构造对象
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            //3.判断查询条件key是否为空, 字符串非空判断StringUtils.isNotEmpty(字符串)
            if (StringUtils.isNotEmpty(requestParams.getKey())) {
                //3.1 不为空全文检索"all"
                boolQueryBuilder.must(QueryBuilders.matchQuery("all", requestParams.getKey()));
            }else {
                //3.2 为空全文检索所有
                boolQueryBuilder.must(QueryBuilders.matchAllQuery());
            }
            //判断查询条件参数category是否有效
            if (StringUtils.isNotEmpty(requestParams.getCategory())){
                boolQueryBuilder.filter(QueryBuilders.termQuery("category", requestParams.getCategory()));
            }
            //判断查询条件参数brand是否有效
            if (StringUtils.isNotEmpty(requestParams.getBrand())){
                boolQueryBuilder.filter(QueryBuilders.termQuery("brand", requestParams.getBrand()));
            }
            //判断查询条件参数maxPrice和minPrice是否有效
            if (requestParams.getMaxPrice()!=null&&requestParams.getMinPrice()!=null){
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").
                        lte(requestParams.getMaxPrice()).
                        gte(requestParams.getMinPrice()));
            }else if (requestParams.getMaxPrice()==null){
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").
                        gte(requestParams.getMinPrice()));
            }else if (requestParams.getMinPrice()==null){
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").
                        lte(requestParams.getMaxPrice()));
            }else {
                System.out.println("null");
            }
            //设置查询
            request.source().query(boolQueryBuilder);
            //设置size为0，不查询文档数据
            request.source().size(0);
            //添加聚合条件
            request.source().aggregation(AggregationBuilders.terms("categoryAgg").field("category").size(100));
            request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(10));
            //执行查询
            SearchResponse response = highLevelClient.search(request,RequestOptions.DEFAULT);

            Map<String,List<String>>resultMap = new HashMap<>();

            //非空判断
            //  if (response.getAggregations()!=null){
            //      //解析分类聚合
            //      Terms categoryAgg = response.getAggregations().get("category");
            //      List<? extends Terms.Bucket> buckets = categoryAgg.getBuckets();
            //      ArrayList<String> categoryList = new ArrayList<>();
            //      for (Terms.Bucket bucket : buckets) {
            //          categoryList.add(bucket.getKeyAsString());
            //      }
            //      resultMap.put("category",categoryList);
            //      //解析 品牌聚合
            //      Terms brand = response.getAggregations().get("brandAgg");
            //      List<? extends Terms.Bucket> brandBuckets = brand.getBuckets();
            //      List<String> brandList = new ArrayList<>();
            //      for (Terms.Bucket bucket : buckets) {
            //          brandList.add(bucket.getKeyAsString());
            //      }
            //      resultMap.put("brand",brandList);
            //  }

            //获取聚合结果
            List<String> categoryList = getKeyListFromAggName(response,"categoryAgg");
            List<String> brandList = getKeyListFromAggName(response,"brandAgg");
            resultMap.put("category",categoryList);
            resultMap.put("brand",brandList);


            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    private List<String> getKeyListFromAggName(SearchResponse response,String aggName) {
        Terms terms = response.getAggregations().get(aggName);
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        List<String> keyList = new ArrayList<>();
        for(Terms.Bucket bucket:buckets){
            String key = bucket.getKeyAsString();
            keyList.add(key);
        }
        return keyList;
    }

    @Autowired(required = false)
    private ObjectMapper objectMapper;
    /**
     * 实现基本搜索功能
     *
     * @param requestParams
     * @return itemdoc
     */
    @Override
    public PageDTO<ItemDoc> list(RequestParams requestParams) {
        //1.判断查询页码 和 每页大小是否为null, 如果为null，设置默认值 page=1 和 size=5
        if (requestParams.getPage()==null) requestParams.setPage(1);
        if (requestParams.getSize()==null) requestParams.setSize(5);
        //2.创建搜索请求对象 SearchRequest
        try {
            SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
            //bool查询构造对象
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            //3.判断查询条件key是否为空, 字符串非空判断StringUtils.isNotEmpty(字符串)
            if (StringUtils.isNotEmpty(requestParams.getKey())) {
                //3.1 不为空全文检索"all"
                boolQueryBuilder.must(QueryBuilders.matchQuery("all",requestParams.getKey()));

            }else {
                //3.2 为空全文检索所有
                boolQueryBuilder.must(QueryBuilders.matchAllQuery());
            }
            //判断查询条件参数category是否有效
            if (StringUtils.isNotEmpty(requestParams.getCategory())){
                boolQueryBuilder.filter(QueryBuilders.termQuery("category", requestParams.getCategory()));
            }

            //判断查询条件参数brand是否有效
            if (StringUtils.isNotEmpty(requestParams.getBrand())){
                boolQueryBuilder.filter(QueryBuilders.termQuery("brand", requestParams.getBrand()));
            }
            //判断查询条件参数maxPrice和minPrice是否有效
            if (requestParams.getMaxPrice()!=null&&requestParams.getMinPrice()!=null){
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").
                        lte(requestParams.getMaxPrice()).
                        gte(requestParams.getMinPrice()));
            }

            //设置高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("name").requireFieldMatch(false).preTags("<font color='red'>").postTags("</font>");
            searchRequest.source().highlighter(highlightBuilder);
            //提分函数
            searchRequest.source().query(QueryBuilders.functionScoreQuery(
                    boolQueryBuilder,
                    new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                            new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                    QueryBuilders.termQuery("isAD","true"),
                                    ScoreFunctionBuilders.weightFactorFunction(10)
                            )
                    }
            ).boostMode(CombineFunction.SUM));
            //4.计算分页起始位置，公式=（当前页-1）* 每页大小
            //5.设置查询分页from和size
            Integer from = (requestParams.getPage()-1)*requestParams.getSize();
            Integer size = requestParams.getSize();
            searchRequest.source().from(from).size(size);

            SearchResponse response = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //8.封装结果并返回
            SearchHits searchHits = response.getHits();
            //9.获取总记录数
            PageDTO<ItemDoc> pageResult = new PageDTO();
            long total =  searchHits.getTotalHits().value;
            pageResult.setTotal(total);
            //10.遍历获取文档集合数据
            //定义集合List<HotelDoc>收集数据
            List<ItemDoc> hotelDocList = new ArrayList<>();
            for (SearchHit searchHit : searchHits) {
                //10.1 获取每个文档的json数据
                String json = searchHit.getSourceAsString();
                //10.2 json转换为HotelDoc对象
                ItemDoc hotelDoc = objectMapper.readValue(json, ItemDoc.class);
                //10.3替换高亮内容
                HighlightField highlightField = searchHit.getHighlightFields().get("name");
                if (highlightField!=null) {
                    hotelDoc.setName(highlightField.getFragments()[0].toString());

                }
                //10.4 将hotelDoc对象添加到集合中
                hotelDocList.add(hotelDoc);
                //11.封装分页数据返回
                pageResult.setList(hotelDocList);
            }
            //返回数据
            return pageResult;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

//
    /**
     * 构建页面传入的搜索条件
     * @param params
     * @return
     */
    private BoolQueryBuilder getBoolQueryBuilder(RequestParams params) {
        //拼接条件（***）
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if(StringUtils.isNotEmpty(params.getKey())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("all",params.getKey()));
        }else{
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        }
        if(StringUtils.isNotEmpty(params.getCategory())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category",params.getCategory()));
        }
        if(StringUtils.isNotEmpty(params.getBrand())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("brand",params.getBrand()));
        }
        if(params.getMinPrice()!=null && params.getMaxPrice()!=null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
        }
        return boolQueryBuilder;
    }

    /**
     * 添加商品
     * @param id
     */
    @Override
    public void insertById(Long id) {
        try {
            //定义测试方法，调用itemMapper获取指定的一条数据返回item对象
            Item item = itemMapper.selectById(id);
            //根据item对象封装到itemdoc对象中
            //   ItemDoc itemDoc = new ItemDoc(item);
            //创建IndexRequest请求对象，并构建dssl添加文档命令
            //构建添加文档命令，格式为POST item/_doc/id
            IndexRequest indexRequest= new IndexRequest("item").id(item.getId().toString());

            String jsonStr = objectMapper.writeValueAsString(item);

            indexRequest.source(jsonStr, XContentType.JSON);
            //执行添加文档命令并返回结果对象
            //  IndexResponse response =
            highLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            // System.out.println(response.getId());
        } catch (Exception e) {
            e.printStackTrace();
            throw  new RuntimeException(e);
        }
    }

    /**
     * 删除指定id商品
     */
    @Override
    public void deleteById(Long id) throws IOException {
        //构建deleteRequest
        DeleteRequest deleteRequest = new DeleteRequest("item").id(id.toString());
        //执行删除方法
        highLevelClient.delete(deleteRequest,RequestOptions.DEFAULT);
    }

}
